﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.DataVisualization;
using System.Windows.Controls.DataVisualization.Charting;
using System.IO;
using Microsoft.Win32;

namespace ACPLogAnalyzer
{
    /// <summary>
    /// Interaction logic for GraphUserControl.xaml
    /// </summary>
    public partial class GraphUserControl : UserControl
    {
        public enum SeriesName { Main, Secondary, Third };

        public delegate void DataPointSelected(object sender, DataPointSelectedEventArgs e);
        public event DataPointSelected DataPointSelectionChanged;

        private SolidColorBrush m_fgBrush;
        private SolidColorBrush m_fgBrushTitle;
        private SolidColorBrush m_bgBrushGraph;
        private SolidColorBrush m_bgKeyBrush;
        private SolidColorBrush m_brushMainLine;
        private SolidColorBrush m_brushSecondaryLine;
        private SolidColorBrush m_brushThirdLine;

        private List<KeyValuePair<object, object>> m_dataSourceSeries1;  // Set by caller to DataSource property 
        public List<KeyValuePair<object, object>> DataSourceSeries1  // string is the x-axis (normally time or date), object is the data to plot
        {
            get
            {
                return m_dataSourceSeries1;
            }
            set
            {
                m_dataSourceSeries1 = value;
                ((LineSeries)lineGraph.Series[0]).ItemsSource = m_dataSourceSeries1;
            }
        }

        private List<KeyValuePair<object, object>> m_dataSourceSeries2;  // Set by caller to DataSourceSeries2 property 
        public List<KeyValuePair<object, object>> DataSourceSeries2
        {
            get
            {
                return m_dataSourceSeries2;
            }
            set
            {
                m_dataSourceSeries2 = value;
                ((LineSeries)lineGraph.Series[1]).ItemsSource = m_dataSourceSeries2;
            }
        }

        private List<KeyValuePair<object, object>> m_dataSourceSeries3;  // Set by caller to DataSource3 property 
        public List<KeyValuePair<object, object>> DataSourceSeries3  // 
        {
            get
            {
                return m_dataSourceSeries3;
            }
            set
            {
                m_dataSourceSeries3 = value;
                ((LineSeries)lineGraph.Series[2]).ItemsSource = m_dataSourceSeries3;
            }
        }

        private LogEventType m_logEventTypeMainSeries;
        public LogEventType LogEventTypeMainSeries
        {
            get { return m_logEventTypeMainSeries; }
            set { m_logEventTypeMainSeries = value; }
        }

        private LogEventType m_logEventTypeTertiarySeries;
        public LogEventType LogEventTypeTertiarySeries
        {
            get { return m_logEventTypeTertiarySeries; }
            set { m_logEventTypeTertiarySeries = value; }
        }

        private void InitText()
        {
            try
            {
                FontWeightConverter fwc = new FontWeightConverter();
                FontStyleConverter fsc = new FontStyleConverter();

                if (Properties.Settings.Default.Plot_FG_Color != null)
                {
                    m_fgBrush = new SolidColorBrush(
                        System.Windows.Media.Color.FromRgb(
                            Properties.Settings.Default.Plot_FG_Color.R,
                            Properties.Settings.Default.Plot_FG_Color.G,
                            Properties.Settings.Default.Plot_FG_Color.B));
                }
                else
                    m_fgBrush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 0, 0));

                // Overall graph text properties...
                lineGraph.FontFamily = new System.Windows.Media.FontFamily(Properties.Settings.Default.Plot_Font_Name);
                lineGraph.FontSize = double.Parse(Properties.Settings.Default.Plot_Font_Size);
                lineGraph.FontWeight = (FontWeight)fwc.ConvertFromString(Properties.Settings.Default.Plot_Font_Weight);
                lineGraph.FontStyle = (FontStyle)fsc.ConvertFromString(Properties.Settings.Default.Plot_Font_Style);
                lineGraph.Foreground = m_fgBrush;
            }
            catch
            {
            }
        }

        private void InitTextTitle()
        {
            try
            {
                FontWeightConverter fwc = new FontWeightConverter();
                FontStyleConverter fsc = new FontStyleConverter();

                if (Properties.Settings.Default.Plot_FG_Color_Title != null)
                {
                    m_fgBrushTitle = new SolidColorBrush(
                        System.Windows.Media.Color.FromRgb(
                            Properties.Settings.Default.Plot_FG_Color_Title.R,
                            Properties.Settings.Default.Plot_FG_Color_Title.G,
                            Properties.Settings.Default.Plot_FG_Color_Title.B));
                }
                else
                    m_fgBrushTitle = new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 0, 0));

                // Title...
                GraphTitle.FontFamily = new System.Windows.Media.FontFamily(Properties.Settings.Default.Plot_Font_Name_Title);
                GraphTitle.FontSize = double.Parse(Properties.Settings.Default.Plot_Font_Size_Title);
                GraphTitle.FontWeight = (FontWeight)fwc.ConvertFromString(Properties.Settings.Default.Plot_Font_Weight_Title);
                GraphTitle.FontStyle = (FontStyle)fsc.ConvertFromString(Properties.Settings.Default.Plot_Font_Style_Title);
                GraphTitle.Foreground = m_fgBrushTitle;
            }
            catch
            {
            }
        }

        private void InitGraphStyles()
        {
            #region Graph background color 
            if (Properties.Settings.Default.Plot_BG_Graph != null)
            {
                m_bgBrushGraph = new SolidColorBrush(
                    System.Windows.Media.Color.FromRgb(
                        Properties.Settings.Default.Plot_BG_Graph.R,
                        Properties.Settings.Default.Plot_BG_Graph.G,
                        Properties.Settings.Default.Plot_BG_Graph.B));
            }
            else
                m_bgBrushGraph = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 255, 255));  // White by default

            lineGraph.Background = m_bgBrushGraph;
            GraphTitle.Background = m_bgBrushGraph;  // Make sure the bg of the title control is the same as the graph
            #endregion

            #region Key background color
            if (Properties.Settings.Default.Plot_BG_Key != null)
            {
                m_bgKeyBrush = new SolidColorBrush(
                    System.Windows.Media.Color.FromRgb(
                        Properties.Settings.Default.Plot_BG_Key.R,
                        Properties.Settings.Default.Plot_BG_Key.G,
                        Properties.Settings.Default.Plot_BG_Key.B));
            }
            else
                m_bgKeyBrush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 255, 255));  // White by default

            lineGraph.LegendStyle = LegendStyle();
            #endregion

            #region Line and DataPoint styles
            if (Properties.Settings.Default.Plot_Main_Line_Color != null)
            {
                m_brushMainLine = new SolidColorBrush(
                    System.Windows.Media.Color.FromRgb(
                        Properties.Settings.Default.Plot_Main_Line_Color.R,
                        Properties.Settings.Default.Plot_Main_Line_Color.G,
                        Properties.Settings.Default.Plot_Main_Line_Color.B));
            }
            else
                m_brushMainLine = new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 0, 255));  // Blue by default

            if (Properties.Settings.Default.Plot_Secondary_Line_Color != null)
            {
                m_brushSecondaryLine = new SolidColorBrush(
                    System.Windows.Media.Color.FromRgb(
                        Properties.Settings.Default.Plot_Secondary_Line_Color.R,
                        Properties.Settings.Default.Plot_Secondary_Line_Color.G,
                        Properties.Settings.Default.Plot_Secondary_Line_Color.B));
            }
            else
                m_brushSecondaryLine = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 0, 0));  // Red by default

            if (Properties.Settings.Default.Plot_Tertiary_Line_Color != null)
            {
                m_brushThirdLine = new SolidColorBrush(
                    System.Windows.Media.Color.FromRgb(
                        Properties.Settings.Default.Plot_Tertiary_Line_Color.R,
                        Properties.Settings.Default.Plot_Tertiary_Line_Color.G,
                        Properties.Settings.Default.Plot_Tertiary_Line_Color.B));
            }
            else
                m_brushThirdLine = new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 255, 0));  // Green by default

            lineGraph.LegendStyle = LegendStyle();
            ((LineSeries)lineGraph.Series[0]).PolylineStyle = PolyLineStyle(SeriesName.Main);
            ((LineSeries)lineGraph.Series[1]).PolylineStyle = PolyLineStyle(SeriesName.Secondary);
            ((LineSeries)lineGraph.Series[2]).PolylineStyle = PolyLineStyle(SeriesName.Third);

            ((LineSeries)lineGraph.Series[0]).DataPointStyle = 
                DataPointStyle(SeriesName.Main, Properties.Settings.Default.Plot_Main_Show_Data_Points);
            
            ((LineSeries)lineGraph.Series[1]).DataPointStyle = 
                DataPointStyle(SeriesName.Secondary, Properties.Settings.Default.Plot_Secondary_Show_Data_Points);
            
            ((LineSeries)lineGraph.Series[2]).DataPointStyle = 
                DataPointStyle(SeriesName.Third, Properties.Settings.Default.Plot_Tertiary_Show_Data_Points);

            #endregion

            #region Chart and Plot area styles
            lineGraph.ChartAreaStyle = ChartAreaStyle();  // Sets the chart area to be transparent
            lineGraph.PlotAreaStyle = PlotAreaStyle();  // Sets the plot area to be transparent
            #endregion
        }

        private void InitSeries1()
        {
            FontWeightConverter fwc = new FontWeightConverter();
            FontStyleConverter fsc = new FontStyleConverter();

            ((LegendItem)lineGraph.LegendItems[0]).FontFamily = new System.Windows.Media.FontFamily(Properties.Settings.Default.Plot_Font_Name);
            ((LegendItem)lineGraph.LegendItems[0]).FontSize = double.Parse(Properties.Settings.Default.Plot_Font_Size);
            ((LegendItem)lineGraph.LegendItems[0]).FontWeight = (FontWeight)fwc.ConvertFromString(Properties.Settings.Default.Plot_Font_Weight);
            ((LegendItem)lineGraph.LegendItems[0]).FontStyle = (FontStyle)fsc.ConvertFromString(Properties.Settings.Default.Plot_Font_Style);
            ((LegendItem)lineGraph.LegendItems[0]).Foreground = m_fgBrush;
        }

        private void InitSeries2()
        {
            FontWeightConverter fwc = new FontWeightConverter();
            FontStyleConverter fsc = new FontStyleConverter();

            ((LegendItem)lineGraph.LegendItems[1]).FontFamily = new System.Windows.Media.FontFamily(Properties.Settings.Default.Plot_Font_Name);
            ((LegendItem)lineGraph.LegendItems[1]).FontSize = double.Parse(Properties.Settings.Default.Plot_Font_Size);
            ((LegendItem)lineGraph.LegendItems[1]).FontWeight = (FontWeight)fwc.ConvertFromString(Properties.Settings.Default.Plot_Font_Weight);
            ((LegendItem)lineGraph.LegendItems[1]).FontStyle = (FontStyle)fsc.ConvertFromString(Properties.Settings.Default.Plot_Font_Style);
            ((LegendItem)lineGraph.LegendItems[1]).Foreground = m_fgBrush;

            ((LegendItem)lineGraph.LegendItems[1]).Visibility = System.Windows.Visibility.Visible;
            ((LineSeries)lineGraph.Series[1]).Visibility = System.Windows.Visibility.Visible;
        }

        private void InitSeries3()
        {
            FontWeightConverter fwc = new FontWeightConverter();
            FontStyleConverter fsc = new FontStyleConverter();

            ((LegendItem)lineGraph.LegendItems[2]).FontFamily = new System.Windows.Media.FontFamily(Properties.Settings.Default.Plot_Font_Name);
            ((LegendItem)lineGraph.LegendItems[2]).FontSize = double.Parse(Properties.Settings.Default.Plot_Font_Size);
            ((LegendItem)lineGraph.LegendItems[2]).FontWeight = (FontWeight)fwc.ConvertFromString(Properties.Settings.Default.Plot_Font_Weight);
            ((LegendItem)lineGraph.LegendItems[2]).FontStyle = (FontStyle)fsc.ConvertFromString(Properties.Settings.Default.Plot_Font_Style);
            ((LegendItem)lineGraph.LegendItems[2]).Foreground = m_fgBrush;

            ((LegendItem)lineGraph.LegendItems[2]).Visibility = System.Windows.Visibility.Visible;
            ((LineSeries)lineGraph.Series[2]).Visibility = System.Windows.Visibility.Visible;
        }

        private Style PolyLineStyle(SeriesName series)
        {
            /* XAML equiv:
             
                <Window.Resources>
                    <Style x:Key="MainPolylineStyle" TargetType="Polyline">
                        <Setter Property="StrokeThickness" Value="5"/>
                    </Style>
                </Window.Resources>
             
             */

            double thickness = 0;
            
            if(series == SeriesName.Main)
                thickness = (double)Properties.Settings.Default.Plot_Main_Thickness;
            else if(series == SeriesName.Secondary)
                thickness = (double)Properties.Settings.Default.Plot_Secondary_Thickness;
            else if(series == SeriesName.Third)
                thickness = (double)Properties.Settings.Default.Plot_Tertiary_Thickness;

            Style style = new Style(typeof(Polyline));
            style.Setters.Add(new Setter(Polyline.StrokeThicknessProperty, thickness));

            return style;
        }

        private Style DataPointStyle(SeriesName series, bool showDataPoints)
        {
            /* XAML equiv:
             
                <Window.Resources>
                    <Style x:Key="MainLineDataPointStyle" TargetType="DVC:LineDataPoint">
                    <Setter Property="Background" Value="Red" />
                    <Setter Property="BorderBrush" Value="White"/>
                    <Setter Property="BorderThickness" Value="1"/>
                    <Setter Property="IsTabStop" Value="False"/>
                    </Style>
                </Window.Resources>
             
             */

            Style style = new Style(typeof(DataPoint));

            if (series == SeriesName.Main)
            {
                style.Setters.Add(new Setter(DataPoint.BackgroundProperty, m_brushMainLine));
                style.Setters.Add(new Setter(DataPoint.BorderBrushProperty, m_brushMainLine));
            }
            else if(series == SeriesName.Secondary)
            {
                style.Setters.Add(new Setter(DataPoint.BackgroundProperty, m_brushSecondaryLine));
                style.Setters.Add(new Setter(DataPoint.BorderBrushProperty, m_brushSecondaryLine));
            }
            else if (series == SeriesName.Third)
            {
                style.Setters.Add(new Setter(DataPoint.BackgroundProperty, m_brushThirdLine));
                style.Setters.Add(new Setter(DataPoint.BorderBrushProperty, m_brushThirdLine));
            }

            style.Setters.Add(new Setter(DataPoint.BorderThicknessProperty, new Thickness(1)));

            if (!showDataPoints)
                style.Setters.Add(new Setter(DataPoint.TemplateProperty, null));  // Nulling DataPoint.TemplateProperty turns OFF the data points

            return style;
        }

        private Style LegendStyle()
        {
            /* XAML equiv:
             
                <DVC:Chart>
                    <DVC:Chart.LegendStyle>
                        <Style TargetType="VIZ:Legend">
                            <Setter Property="BorderBrush" Value="Transparent"/>
                            <Setter Property="Background" Value="Transparent"/>
                            <Setter Property="Height" Value="100" />
                        </Style>
                    </DVC:Chart.LegendStyle>
                    :
                    :
                </DVC:Chart>
             
             */

            Style style = null;
            try
            {
                style = new Style(typeof(Legend));
                style.Setters.Add(new Setter(Legend.BackgroundProperty, m_bgKeyBrush));
                style.Setters.Add(new Setter(Legend.BorderBrushProperty, m_bgKeyBrush));
                style.Setters.Add(new Setter(Legend.HeightProperty, 100.0));

                if (Properties.Settings.Default.Plot_BG_Key_Transparent)
                    m_bgKeyBrush.Opacity = 0;
            }
            catch
            {
            }
            return style;
        }

        private Style ChartAreaStyle()
        {
            // Here we make the chart area TRANSPARENT, so the graph bg color setting will apply to the chart/plot area too

            // This style works for both the plot area (where the data is plotted) and chart area (the large border around the graph)
            /*
                The style can also be set in XAML:
                
                <DVC:Chart>
                    <DVC:Chart.PlotAreaStyle>
                        <Style TargetType="Panel" x:Name="plotAreaStyle">
                            <Setter Property="Background" Value="Transparent"/>
                        </Style>
                    </DVC:Chart.PlotAreaStyle>
            
                    <DVC:Chart.ChartAreaStyle>
                        <Style TargetType="Panel">
                            <Setter Property="Background" Value="Transparent" />
                        </Style>
                    </DVC:Chart.ChartAreaStyle>
                :
                :
                </DVC:Chart>
            */

            Color background = Color.FromRgb(0, 0, 0);
            var brush = new SolidColorBrush(background);
            brush.Opacity = 0;

            Style style = new Style(typeof(Panel));
            style.Setters.Add(new Setter(Panel.BackgroundProperty, brush));
            
            return style;
        }

        private Style PlotAreaStyle()
        {
            return ChartAreaStyle();
        }

        public GraphUserControl() : this(LogEventType.None, LogEventType.None)
        {
        }

        public GraphUserControl(LogEventType mainSeries, LogEventType tertiarySeries)
        {
            InitializeComponent();
            UpdateStyles();

            m_logEventTypeMainSeries = mainSeries;
            m_logEventTypeTertiarySeries = tertiarySeries;
        }

        public void RefreshData()
        {
            ((LineSeries)lineGraph.Series[0]).Refresh();
            ((LineSeries)lineGraph.Series[1]).Refresh();
            ((LineSeries)lineGraph.Series[2]).Refresh();
        }

        public void UpdateStyles()
        {
            InitText();
            InitTextTitle();
            InitGraphStyles();
            InitSeries1();
            InitSeries2();
            InitSeries3();
        }

        public void ShowSecondarySeries(bool show)
        {
            if (show)
            {
                ((LegendItem)lineGraph.LegendItems[1]).Visibility = System.Windows.Visibility.Visible;
                ((LineSeries)lineGraph.Series[1]).Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                ((LegendItem)lineGraph.LegendItems[1]).Visibility = System.Windows.Visibility.Hidden;
                ((LineSeries)lineGraph.Series[1]).Visibility = System.Windows.Visibility.Hidden;
            }
        }

        public void ShowThirdSeries(bool show)
        {
            if (show)
            {
                ((LegendItem)lineGraph.LegendItems[2]).Visibility = System.Windows.Visibility.Visible;
                ((LineSeries)lineGraph.Series[2]).Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                ((LegendItem)lineGraph.LegendItems[2]).Visibility = System.Windows.Visibility.Hidden;
                ((LineSeries)lineGraph.Series[2]).Visibility = System.Windows.Visibility.Hidden;
            }
        }

        private void MenuItemExportExcel_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();  // Create an instance of Excel
                excel.Visible = true;  // Show it
                excel.Workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);  // Create a new, blank sheet

                excel.ActiveCell.set_Item(1, 1, xAxis.Title.ToString());  // Add data to R1C1
                excel.ActiveCell.set_Item(1, 2, lineSeries.Title.ToString());  // Add data to R1C2

                int rowIndex = 2;
                foreach (KeyValuePair<object, object> kvp in m_dataSourceSeries1)
                {
                    excel.ActiveCell.set_Item(rowIndex, 1, kvp.Key);
                    excel.ActiveCell.set_Item(rowIndex, 2, kvp.Value.ToString());
                    rowIndex++;
                }

                if (m_dataSourceSeries3 != null && m_dataSourceSeries3.Count > 0)
                {
                    rowIndex++;
                    excel.ActiveCell.set_Item(rowIndex, 1, xAxisTertiary.Title.ToString());
                    excel.ActiveCell.set_Item(rowIndex, 2, lineSeries3.Title.ToString());
                    rowIndex++;

                    foreach (KeyValuePair<object, object> kvp in m_dataSourceSeries3)
                    {
                        excel.ActiveCell.set_Item(rowIndex, 1, kvp.Key);
                        excel.ActiveCell.set_Item(rowIndex, 2, kvp.Value.ToString());
                        rowIndex++;
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show("Unable to export data to Excel:\n\n" + ex.Message, "Excel Interop Error");
            }
        }

        private void MenuItemExportCSV_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string timestamp = DateTime.Now.ToLongTimeString();
                timestamp = timestamp.Replace(":", "");
                
                string title = GraphTitle.Text.Trim().Replace(" ", "_");

                string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
                    @"\ACPLogAnalyzer-Data-" + title + "-" + timestamp + ".csv";

                using (StreamWriter outfile = new StreamWriter(path))
                {
                    outfile.WriteLine(xAxis.Title.ToString() + "," + lineSeries.Title.ToString());
                    foreach (KeyValuePair<object, object> kvp in m_dataSourceSeries1)
                    {
                        outfile.WriteLine(kvp.Key + "," + kvp.Value.ToString());
                    }

                    if (m_dataSourceSeries3 != null && m_dataSourceSeries3.Count > 0)
                    {
                        outfile.WriteLine("");
                        outfile.WriteLine(xAxisTertiary.Title.ToString() + "," +  lineSeries3.Title.ToString());
                        foreach (KeyValuePair<object, object> kvp in m_dataSourceSeries3)
                        {
                            outfile.WriteLine(kvp.Key + "," + kvp.Value.ToString());
                        }
                    }
                }

                MessageBox.Show("Report saved on your Desktop as: \n\nACPLogAnalyzer-Export-" + title + "-" + timestamp + ".csv", "Data Exported");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error Saving Report");
            }
        }

        private void MenuItemShowHideAverage_Click(object sender, RoutedEventArgs e)
        {
            if (ctxMenuShowHideAvg.Header.ToString().StartsWith("Hide"))
            {
                ctxMenuShowHideAvg.Header = "Show " + lineSeries2.Title;
                ShowSecondarySeries(false);
            }
            else
            {
                ctxMenuShowHideAvg.Header = "Hide " + lineSeries2.Title;
                ShowSecondarySeries(true);
            }
        }

        private void MenuItemShowHideTertiary_Click(object sender, RoutedEventArgs e)
        {
            if (ctxMenuShowHideTertiary.Header.ToString().StartsWith("Hide"))
            {
                ctxMenuShowHideTertiary.Header = "Show " + lineSeries3.Title;
                ShowThirdSeries(false);
            }
            else
            {
                ctxMenuShowHideTertiary.Header = "Hide " + lineSeries3.Title;
                ShowThirdSeries(true);
            }
        }

        private void Grid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            // Do we need to hide the Show/Hide 'Tertiary' command?
            if (DataSourceSeries3 == null || DataSourceSeries3.Count == 0)
                ctxMenuShowHideTertiary.Visibility = System.Windows.Visibility.Collapsed;
            else
                ctxMenuShowHideTertiary.Visibility = System.Windows.Visibility.Visible;

            // Customize the menu text...
            if (ctxMenuShowHideTertiary.Header.ToString().StartsWith("Hide"))
                ctxMenuShowHideTertiary.Header = "Hide " + lineSeries3.Title;
            else
                ctxMenuShowHideTertiary.Header = "Show " + lineSeries3.Title;

            if (ctxMenuShowHideAvg.Header.ToString().StartsWith("Hide"))
                ctxMenuShowHideAvg.Header = "Hide " + lineSeries2.Title;
            else
                ctxMenuShowHideAvg.Header = "Show " + lineSeries2.Title;
        }

        private void lineSeries1MouseUp(object sender, MouseButtonEventArgs e)
        {
            KeyValuePair<object, object> dp = GetDataPointAtMousePosition(
                lineSeries, e.GetPosition(lineSeries), m_dataSourceSeries1);

            if(dp.Key != null && dp.Value != null)
                OnDataPointSelected(dp, m_logEventTypeMainSeries);  // Raise the DataPointSelected event
        }

        private void lineSeries3MouseUp(object sender, MouseButtonEventArgs e)
        {
            KeyValuePair<object, object> dp = GetDataPointAtMousePosition(
                lineSeries3, e.GetPosition(lineSeries3), m_dataSourceSeries3);

            if (dp.Key != null && dp.Value != null)
                OnDataPointSelected(dp, m_logEventTypeTertiarySeries);  // Raise the DataPointSelected event
        }

        private KeyValuePair<object, object> GetDataPointAtMousePosition(
            LineSeries series, Point position, List<KeyValuePair<object, object>>dataPointList)
        {
            int? dataPointIndex = FindNearestPointIndex(series.Points, position);
            
            if (dataPointIndex == null)
                return new KeyValuePair<object, object>(null, null);
            else
                return dataPointList[(int)dataPointIndex];
        }

        private int? FindNearestPointIndex(PointCollection points, Point newPoint)
        {
            if (points == null || !points.Any())
                return null;

            Func<Point, Point, double> getLength = (p1, p2) => Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
            var items = points.Select((p, i) => new { Point = p, Length = getLength(p, newPoint), Index = i });
            double minLength = items.Min(item => item.Length);

            return items.First(item => item.Length == minLength).Index;
        }

        protected void OnDataPointSelected(KeyValuePair<object, object> data, LogEventType logEventType)
        {
            if (DataPointSelectionChanged != null)
                DataPointSelectionChanged(this, new DataPointSelectedEventArgs(data, logEventType));
        }

    }

    /// <summary>
    /// Custom event args class
    /// </summary>
    public class DataPointSelectedEventArgs : EventArgs
    {
        private KeyValuePair<object, object> m_data;
        public KeyValuePair<object, object> Data
        {
            get { return m_data; }
            set { m_data = value; }
        }

        private LogEventType m_logEventType;
        public LogEventType EventType
        {
            get { return m_logEventType; }
            set { m_logEventType = value; }
        }

        public DataPointSelectedEventArgs()
            : this(new KeyValuePair<object, object>(null, null), LogEventType.None)
        {
        }

        public DataPointSelectedEventArgs(KeyValuePair<object, object> data, LogEventType logEventType)
        {
            m_data = data;
            m_logEventType = logEventType;
        }
    }
}
